/*
 * 创建[Object]实例 添加属性 方法
 * 
 * 早期开发者频繁使用这个方式创建 这个方式有个明显的缺点:当创建多个实例时 属性 方法都相同 但还是需要复制相同的代码 重用性很差
 * 为了解决这个问题 引入了 [工厂模式]
 * 
 */

var person = new Object();
person.name = 'Kevin Nick';
person.age = 25;
person.job = 'SE: Software Engineer';
person.sayName = function() {
	alert(this.name);
};

/*
 * [工厂]模式
 * 
 * 工厂模式解决了重用性问题 但是每次创建对象时也需要创建方法(*1) 很明显 对于实例来说是 方法共享的 属性独立的
 * 
 */

function createPerson(name, age, job) {
	var o = new Object();
	o.name = name;
	o.age = age;
	o.job = job;
	o.sayName = function() {
		alert(this.name);
	};
	return o;
}

var person1 = createPerson('Nicholas', 29, 'Software Engineer');
var person2 = createPerson('Greg', 27, 'Doctor');

// alert(person1.sayName == person2.sayName) -> false

/*
 * [构造方法]模式
 * 
 * 以下几个注意点
 * 1.没有显式创建对象 (no new Object())
 * 2.在构造方法中为属性 方法分配作用域 (this -> new object)
 * 3.无 return
 * 4.函数名 首字母大写 
 * 5.person1.constructor == Person -> true
 * 6.person1 instanceof Person -> true 实例标识为特定对象类型 相对于[工厂模式]是个很大的优势
 * 
 * 此方法非常类似OOP的Java的类
 */

function Person(name, age, job) {
	this.name = name;
	this.age = age;
	this.job = job;
	this.sayName = function() {
		alert(this.name);
	};
}

var person1 = new Person('Nicholas', 29, 'Software Engineer');
var person2 = new Person('Greg', 27, 'Doctor');

// alert(person1.sayName == person2.sayName) -> false

/*alert(person1 instanceof Object);
alert(person1 instanceof Person);*/

/* ---------------------------	函数的调用方式	------------------------- */

// 构造方法
var person = new Person('Nicholas', 29, 'Software Engineer');
// person.sayName();// Nicholas

// 普通函数
Person('Greg', 27, 'Doctor'); // 注意 作用域为 全局对象window
// window.sayName(); // Greg

// 普通函数和call
var o = new Object();
Person.call(o, 'Kristen', 25, 'Nurse'); // 作用范围 -> 对象o
// o.sayName(); // Kristen

/*
 * [修正构造方法]模式  
 * 
 * 构造方法模式显然还是不够好 依然存在(*1) 
 * 为了使方法共享于个实例间 将其置于全局 显得凌乱 显然此方法实际只与创建的对象有关联(*2)
 * 
 */


function Person(name, age, job) {
	this.name = name;
	this.age = age;
	this.job = job;
	this.sayName = sayName;
}

function sayName() {
	alert(this.name);
}

var person1 = new Person('Nicholas', 29, 'Software Engineer');
var person2 = new Person('Greg', 27, 'Doctor');

// alert(person1.sayName == person2.sayName) -> true

/*
 * [原型]模式  
 * 
 * 为解决(*2) 引入原型模式
 * 
 * 显然这个解决方案不够完美 构造方法没有参数 所有属性 方法被实例间共享
 * 当然可以在对象创建后被独立修改  此方案不够完美 
 * 
 */

function Person() {}

Person.prototype.name = 'Nicholas';
Person.prototype.age = 29;
Person.prototype.job = 'Software Engineer';
Person.prototype.sayName = function() {
	alert(this.name);
};

var person1 = new Person();
// person1.sayName(); // Nicholas

var person2 = new Person();
person2.name = 'Kevin';
// person2.sayName(); // Nicholas

// alert(person1.sayName == person2.sayName); // true

/*
 * [构造方法+原型]模式  
 * 
 * 此方案同时解决了 (*1)(*2) 似乎很完美
 */

function Person(name, age, job) {
	this.name = name;
	this.age = age;
	this.job = job;
	this.friends = ['Shelby', 'Court'];
}

Person.prototype = {
	constructor	: Person,
	sayName		: function() {
		alert(this.name);
	}
};

var person1 = new Person('Nicholas', 29, 'Software Engineer');
var person2 = new Person('Greg', 27, 'Doctor');

person1.friends.push('Van');

// alert(person1.friends); // 'Shelby,Court,Van'
// alert(person2.friends); // 'Shelby,Court'
// alert(person1.friends === person2.friends); // false
// alert(person1.sayName === person2.sayName); // true
